package org.leafstar.shortlink.admin.common.biz.user;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.leafstar.shortlink.admin.common.convention.exception.ClientException;
import org.leafstar.shortlink.admin.common.convention.result.Results;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 用户信息传输过滤器
 */
@Slf4j
@RequiredArgsConstructor
public class UserTransmitFilter implements Filter {
    private final StringRedisTemplate stringRedisTemplate;
    private static final List<String> IGNORE_URI = List.of(
            "/api/short-link/admin/v1/user/check-login",
            "/api/short-link/admin/v1/user/login",
            "/api/short-link/admin/v1/user/has-username"
    );

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String requestURI = httpServletRequest.getRequestURI();
        //特定链接跳过
        if (!IGNORE_URI.contains(requestURI)) {
            String method = httpServletRequest.getMethod();
            if (!(Objects.equals("/api/short-link/admin/v1/user", requestURI) && Objects.equals(method, "POST"))) {
                Cookie[] cookies = httpServletRequest.getCookies();
                String token = null, username = null;
                //cookie里可能携带其他很多值
                try {
                    token = Arrays.stream(cookies)
                            .filter(c -> "token".equals(c.getName()))
                            .findFirst()
                            .map(Cookie::getValue)
                            .get();
                    username = Arrays.stream(cookies)
                            .filter(c -> "username".equals(c.getName()))
                            .findFirst()
                            .map(Cookie::getValue)
                            .get();
                } catch (Exception e) {
                    log.warn("未携带cookies");
                }
                if (StrUtil.isBlank(token))
                    token = httpServletRequest.getHeader("token");
                if (StrUtil.isBlank(username))
                    username = httpServletRequest.getHeader("username");
                if (!StrUtil.isAllNotBlank(username, token)) {
                    returnJson((HttpServletResponse) servletResponse, JSON.toJSONString(Results.failure(new ClientException("token验证失败"))));
                }
                try {
                    Object userJson = stringRedisTemplate.opsForHash().get("login_" + username, token);
                    Optional.ofNullable(userJson).ifPresentOrElse(u -> {
                        UserInfoDTO curUser = JSON.parseObject(userJson.toString(), UserInfoDTO.class);
                        UserContext.setUser(curUser);
                    }, () -> returnJson((HttpServletResponse) servletResponse, JSON.toJSONString(Results.failure(new ClientException("token验证失败")))));
                } catch (Exception e) {
                    returnJson((HttpServletResponse) servletResponse, JSON.toJSONString(Results.failure(new ClientException("token验证失败"))));
                }
            }
        }

        try {
            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            UserContext.removeUser();
        }
    }

    private void returnJson(HttpServletResponse response, String json) {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=utf-8");
        try (PrintWriter writer = response.getWriter()) {
            writer.println(json);
        } catch (IOException e) {
            log.warn("获得writer异常");
        }
    }
}